package jehc.cloud.oauth.client.publisher;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import jehc.cloud.common.util.StringUtil;
import jehc.cloud.oauth.client.vo.ChannelEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @Desc
 * @Author 邓纯杰
 * @CreateTime 2012-12-12 12:12:12
 */
@Component
@Slf4j
@Order(2)
public class NettyClient {

    public Map<String, ChannelEntity> channelFutureMap = new ConcurrentHashMap<>();//全局Channel维护

    @Value("${jehc.oauth.hps}")
    private String hps;//集群服务端IP+端口（如：192.168.1.100:22088,192.168.1.100:22089）

    @Value("${jehc.oauth.retryTime:20}")
    private Integer retryTime;//重试时间（连接失败，多久开始重试连接：默认20s）

    @Autowired
    private NettyClient nettyClient;

    @Value("${jehc.oauth.oauthServerId:oauthServer}")
    private String oauthServerId;//客户端id（每个服务对应一个客户端唯一id）

    @Value("${jehc.oauth.oauthServerGroupId:oauthServer}")
    private String oauthServerGroupId;//组Id（可以存多个服务共享一个组Id）

    @PostConstruct
    public void start() {
       initChannel();
    }


    /**
     * 初始化Bootstrap
     */
    public Bootstrap initBootstrap(EventLoopGroup group) {
        if (null == group) {
            group = new NioEventLoopGroup();
        }
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group).channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .handler(new NettyClientInitializer(nettyClient, oauthServerGroupId, oauthServerId));
        return bootstrap;
    }

    /**
     * 初始化服务端Channel
     * @return
     */
    public void initChannel() {
        Bootstrap bootstrap = initBootstrap(null);
        if (!StringUtil.isEmpty(hps)) {
            String[] hpsArray = hps.split(",");
            if (null != hpsArray) {
                for (String hpsTemp : hpsArray) {
                    if (!StringUtil.isEmpty(hpsTemp)) {
                        String[] array = hpsTemp.split(":");
                        if (null != array && array.length == 2) {
                            bootstrap.remoteAddress(array[0], new Integer(array[1]));
                            //异步连接tcp服务端
                            ChannelFuture future = bootstrap.connect().addListener((ChannelFuture futureListener) -> {
                                final EventLoop eventLoop = futureListener.channel().eventLoop();
                                if (!futureListener.isSuccess()) {
                                    //服务器未启动 连接tcp服务器不成功
                                    log.info(hpsTemp + "初次连接与服务端断开连接!在"+retryTime+"s之后,尝试重连!");
                                    //10秒后重连
                                    eventLoop.schedule(() -> doConnect(bootstrap, array[0], new Integer(array[1])), retryTime, TimeUnit.SECONDS);
                                }else{
                                    log.info(hpsTemp + "初次连接与服务端成功!");
                                }
                            });
                            channelFutureMap.put(hpsTemp, new ChannelEntity(future,array[0],new Integer(array[1]),future.isSuccess()));//存放
                        }
                    }
                }
            }
        }
    }

    /**
     * 重连服务端
     * @param bootstrap
     * @param host
     * @param port
     */
    public void doConnect(Bootstrap bootstrap,String host,Integer port) {
        try {
            if (bootstrap != null) {
                bootstrap.remoteAddress(host, port);
                ChannelFuture f = bootstrap.connect().addListener((ChannelFuture futureListener) -> {
                    final EventLoop eventLoop = futureListener.channel().eventLoop();
                    if (!futureListener.isSuccess()) {
                        log.info("服务端："+host+"，端口："+port + "服务器断线-----与服务端断开连接!在"+retryTime+"s之后，尝试重连!");
                        eventLoop.schedule(() -> doConnect(bootstrap, host, port), retryTime, TimeUnit.SECONDS);
                    }
                });
                channelFutureMap.put(host+":"+port, new ChannelEntity(f,host,port,f.isSuccess()));//覆盖
            }
        } catch (Exception e) {
            log.error("客户端连接失败,{}" , e.getMessage());
        }
    }
}
